---
layout: howTo
---
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements. See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership. The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied. See the License for the
    specific language governing permissions and limitations
    under the License.
-->

<!-- Main -->
<div id="main">

    <!-- Introduction -->
    <section id="intro" class="main special">
        <div class="">
            <div class="content align-left">
                <header class="major">
                    <h1><b>Configure Custom Listeners</b></h1>
                </header>

                <p>
                    This document will help you understand what is Mailbox Listener.
                    Then you will have a chance to implement your own Mailbox Listener and configure it to use it in James server.
                </p>

                <ul>
                    <li>What is Mailbox Listener</li>
                    <li>How to use a custom Mailbox Listener in James</li>
                </ul>

                <header class="major">
                    <h2><b>What is Mailbox Listener</b></h2>
                </header>

                <p>
                    Mailbox Listener is a component in James Mailbox System.
                    Each time an action is applied on a mailbox(adding, deleting), or on an email(adding, deleting, updating flags...),
                    then an event representing that action is generated and delivered to all the Listeners that had been registered before.
                    After receiving events, listeners retrieve information from the events then execute their business
                    (Indexing emails in OpenSearch, updating quota of users, detecting spam emails...)
                </p>

                <p>
                    There are two kinds of Listener registration:
                </p>
                <ul>
                    <li>
                        <b>Group Registration</b>: a Group Registration will listen for all events fired and will deliver each event only once per group within a distributed topology.
                        That means if there are three listeners registered to the same group, each time an event is fired, only one of these three listeners can receive that event.
                        You can write your own custom Listener and configure James to register it as a Group Registration.
                    </li>
                    <li>
                        <b>Key Registration</b>: a Key Registration will listen only for events it is interested in, and with each event fired to a Key Registration, it will be
                        delivered to all registered listeners. That means if there are three listeners registered to the same key, each time an event is fired, all of three listeners will receive that event.
                        At the moment, James doesn't support to configure custom Listener for Key Registration.
                        This feature is used internally to implement things like IMAP IDLE aka notifications.
                        Therefore, it's not exposed through configurations as it makes little sense
                    </li>
                </ul>

                <header class="major">
                    <h2><b>How to use a custom Mailbox Listener in James</b></h2>
                </header>

                <p>
                    <b>prerequisite</b>: custom Mailbox Listeners can only work with James Guice products.
                </p>

                <header class="major">
                    <h3><b>Use the custom SetCustomFlagOnBigMessages in James</b></h3>
                </header>

                <p>
                    Once you have a custom Listener, it's very simple to setup James with that Listener.
                    In this example, we will use the
                    <a href="https://github.com/apache/james-project/blob/master/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java">SetCustomFlagOnBigMessages</a>
                    which will listen events fired after emails are appended to users mailboxes,
                    then for each email added event, determine the size of added email by getting size information from the event.
                    If the size of the email is greater than or equals 1 MB, then SetCustomFlagOnBigMessages will add a "BIG_MESSAGE" flag to that email
                </p>

                <header class="major">
                    <h3><b>Starting James with SetCustomFlagOnBigMessages</b></h3>
                </header>

                <p>You can retrieve the sources of this mini-project on <a href="https://github.com/apache/james-project/tree/master/examples/custom-listeners">GitHub</a></p>


                <p>We will take the simplest James InMemory version for the example</p>

                <p>First, we will need to compile our project with <code>mvn clean install</code>. A jar will be outputted in the target directory.</p>

                <p>Second, we will write the <code>listeners.xml</code> file expressing the logic we want. In this case, we want to use only the BigMessageListener.</p>
                <pre><code>
&lt;listeners&gt;
    &lt;listener&gt;
        &lt;class&gt;org.apache.james.examples.custom.listeners.SetCustomFlagOnBigMessages&lt;/class&gt;
    &lt;/listener&gt;
&lt;/listeners&gt;
                </code></pre>

                <p>Finally, we will start a James server using that. We will rely on docker default image for simplicity.
                    We need to be using the <code>listeners.xml</code> configuration that we had been writing and position the jar in the extensions-jars folder (specific to guice).
                    This can be achieved with the following command:</p>

                <pre><code>docker run -p "25:25" -p "143:143" \
               -v "$PWD/src/main/resources/listeners.xml:/root/conf/listeners.xml" \
               -v "$PWD/target/custom-listeners:/root/extensions-jars/custom-listeners" \
        apache/james:memory-latest --generate-keystore</code></pre>

                <header class="major">
                    <h3><b>Verifying the result of the setup</b></h3>
                </header>
                <p>
                    Now that we have a proper James server on our local machine with custom listeners loaded, we are able to use them.
                    To verify our work, here is this simple scenario:
                </p>
                <ul>
                    <li>Use James CLI to create user1@james.local/password1</li>
                    <li>Use James CLI to create user2@james.local/password2</li>
                    <li>Use a mail client to connect to user1, send a big email to use2</li>
                    <li>Use IMAP command to see the flags of the email user2 had received</li>
                </ul>

                <p>Use James CLI to provision users</p>
                <pre><code>
$ docker exec -it james /bin/bash
$ java -jar james-cli.jar AddUser user1@james.local password1
$ java -jar james-cli.jar AddUser user2@james.local password2
$ exit
                </code></pre>

                <p>
                    Use thunderbird or any mail client on your local machine to connect with user1 and user2.
                    The configuration should point to smpt server at <code>localhost:25</code>, and imap server at <code>localhost:143</code>.
                    Use these credentials: user1@james.local/password1 and user2@james.local/password2
                </p>
                <p>
                    After that, use user1@james.local account to sent a big email to user2@james.local, the size of the emails should be greater than 1 MB.
                    One of the simplest ways is to attach a picture bigger than 1MB to the mail.
                </p>
                <p>
                    If the mail client had sent a mail to user2@james.local, then you can see that this email appeared in user2 INBOX.
                    We can see its flags by using the following IMAP command on your local host.
                </p>
                <pre><code>
$ openssl s_client -connect localhost:993

# Login by user2
A1 LOGIN user2@james.local password2

# Select user2's INBOX
A1 SELECT INBOX

# Search for all emails in user2's INBOX. The result should be: * SEARCH 1. Where 1 is the UID of the email which had been sent before
A1 UID SEARCH ALL

# Display all flags of that email. The result should be: * 1 FETCH (FLAGS (\Recent \Seen BIG_MESSAGE)). You can see that BIG_MESSAGE has appeared
A1 FETCH 1 (FLAGS)
                </code></pre>
                <p>
                    That's it, we are now sure that our SetCustomFlagOnBigMessages worked !
                    Now that you have learned how to set up a custom Listener, you can follow this setup to add your own !
                </p>
            </div>
            <footer class="major">
                <ul class="actions align-center">
                    <li><a href="index.html" class="button">go back to other how-tos</a></li>
                </ul>
            </footer>
        </div>
    </section>

</div>
